﻿using System;
using System.IO;
using System.Threading;

using Microsoft.Coding4Fun.TweetCraft.Twitter;

using Moq;

using NUnit.Framework;

namespace Microsoft.Coding4Fun.TweetCraft.Tests
{
    [TestFixture]
    public class TwitterDispatcherServiceTest
    {
        private Mock<ITwitterClient> twitterMock;

        private ITwitterDispatcherService twitterDispatcherService;

        [SetUp]
        public void SetUp()
        {
            // Initialize TwitterClient mock
            twitterMock = new Mock<ITwitterClient>();

            // Initialize Twitter dispatch service with mock objects
            twitterDispatcherService = new TwitterDispatcherService(twitterMock.Object);
        }

        [TearDown]
        public void TearDown()
        {
            if (twitterDispatcherService != null)
                ((IDisposable)twitterDispatcherService).Dispose();
        }

        [Test]
        public void AutoTweetPictureTest()
        {
            string picturePath = Path.Combine(Environment.CurrentDirectory, "WoWScrnShot.jpg");

            // Set up expectations on TwitterClient
            twitterMock.Setup(twitter => twitter.UploadAndPost(picturePath, It.IsAny<string>()))
                .Verifiable();

            // Set current directory as the picture directory
            twitterDispatcherService.PictureDirectory = Environment.CurrentDirectory;

            // Enable AutoTweeting of pictures
            twitterDispatcherService.AutoTweetPictures = true;

            // Reduce the dispatch period
            twitterDispatcherService.DispatchPeriod = TimeSpan.FromSeconds(1);

            // Add a new picture to the picture directory
            File.WriteAllBytes(picturePath, new byte[0]);

            // Wait for the dispatcher service to pick up file
            Thread.Sleep(TimeSpan.FromSeconds(5));

            try
            {
                // Verify expectations
                twitterMock.VerifyAll();
            }
            finally
            {
                // Delete test file
                File.Delete(picturePath);
            }
        }

        [Test]
        public void QueueTweetTest()
        {
            const string message = "Hello Twitter!";

            // Set up Twitter mock
            twitterMock.Setup(twitter => twitter.AddTweet(message))
                .Returns(new Tweet
                         {
                             Message = message
                         })
                .Verifiable();

            // Create an auto reset event to signal that the event was raised
            var tweetedEvent = new AutoResetEvent(false);

            // Reduce the dispatch period
            twitterDispatcherService.DispatchPeriod = TimeSpan.FromSeconds(1);

            // Subscribe to the Tweeted event
            twitterDispatcherService.Tweeted += delegate(object sender, TweetEventArgs e)
                                                {
                                                    // Assert that the tweet originates from the right source
                                                    Assert.AreEqual(TweetSource.TweetCraft, e.Source);

                                                    // Assert that the tweet contains the correct message
                                                    Assert.AreEqual(message, e.Tweet.Message);

                                                    // Signal that the event was called
                                                    tweetedEvent.Set();
                                                };

            // Queue a tweet into the dispatcher service
            twitterDispatcherService.QueueTweet(new Tweet
                                                {
                                                    Message = message
                                                });

            // Wait for the Tweeted event to be raised
            if (!tweetedEvent.WaitOne(TimeSpan.FromSeconds(10)))
                Assert.Fail("Timed out while waiting for Tweeted event.");
        }
    }
}
